module.exports = (EdtApi) => {
    "use strict";
    let handler, chatResult, chatId = "", chatTitle = "", id = "", title = "", dbVersion = 1530, indexdb, count = 0, friendList = [], chatIdMap = {}, scrollTimer, scrollView, isNewVersion = false;
    function setTheme(theme = "light") {
        localStorage.setItem("theme", theme);
        localStorage.setItem("system-theme-mode", "false");
        let classList = document.body?.classList;
        if (!classList) return;
        classList.remove("dark" == theme ? "light" : "dark");
        classList.add("dark" == theme ? "dark" : "light");
    }
    window.addEventListener('load', () => {
        let theme = localStorage.getItem("edt-theme");
        if (theme) setTheme(theme);
    });
    function resolveChatIdMap(key) {
        if (chatIdMap[key]) {
            if (key?.includes(".us")) {
                return {
                    id: key,
                    name: chatIdMap[key]
                }
            } else return {
                id: chatIdMap[key],
                name: key
            }
        }
        return null;
    }
    function getTitle() {
        let titleStr = "";
        let titleEl = document.querySelector('header span[dir="auto"]');
        if (titleEl) {
            if (!titleEl.querySelector('.emoji')) {
                titleStr = titleEl.textContent || '';
            } else {
                titleEl.childNodes?.forEach(child => {
                    if (child.nodeName == '#text') {
                        titleStr += child.textContent || "";
                    } else if (child.nodeName == 'IMG') {
                        titleStr += child.alt || "";
                    }
                });
            }
        }
        return titleStr;
    }
    async function getChatTitle(times = 0) {
        title = "";
        let titleEl = document.querySelector('header span[dir="auto"]');
        if (titleEl) {
            if (!titleEl.querySelector('.emoji')) {
                title = titleEl.textContent || '';
            } else {
                titleEl.childNodes?.forEach(child => {
                    if (child.nodeName == '#text') {
                        title += child.textContent || "";
                    } else if (child.nodeName == 'IMG') {
                        title += child.alt || "";
                    }
                });
            }
        }
        if (title && title != chatTitle) {
            chatTitle = title;
            return title;
        }
        await EdtApi.sleep(50);
        if (times > 5) return title;
        times++;
        return getChatTitle(times);
    }
    async function getChatId(times = 0) {
        id = "";
        title = getTitle();
        if (isNewVersion) {
            if (!title) {
                if (times > 10) return id;
                times++;
                return getChatId(times);
            }
            id = title;
            let chatItem, chatMap;
            chatResult = await readChat();
            chatItem = chatResult?.find(item => item.name == title);
            if (chatItem) {
                id = chatItem.id;
            } else {//从页面消息列表获取Id
                let idEl = document.querySelector('#main .copyable-area div[role="application"] div[role="row"] div[data-id]');
                let ids, idStr = idEl?.getAttribute("data-id") || "";
                if (idStr?.includes(".us")) ids = idStr.split("_");
                if (ids?.length > 1) {//保存新的对应关系
                    id = ids[1];
                    let oldName = chatIdMap[id]?.name;
                    if (oldName && chatIdMap[oldName]) delete chatIdMap[oldName];
                    chatIdMap[title] = id;
                    chatIdMap[id] = title;
                    localStorage.setItem("chat-id-map", JSON.stringify(chatIdMap));
                } else {
                    chatMap = resolveChatIdMap(title);
                    id = chatMap?.id || title;
                }
            }
        } else id = title;
        if (id && id != chatId) return id;
        await EdtApi.sleep(50);
        if (times > 5) return id;
        times++;
        return getChatId(times);
    }
    function isGroup(chatId = "") {
        // console.log("chatId:", chatId);
        //if (chatId) return chatId.includes("@g.us");
        let el = document.querySelector("#main>header>div:nth-child(2)>div:nth-child(2)>span");
        if (!el) return false;
        let title = el.getAttribute('title');
        if (!title) return false;
        if (
            title.indexOf('群组') > -1 ||
            title.indexOf('您') > -1 ||
            title.indexOf('You') > -1 ||
            title.indexOf('这是社群') > -1 ||
            title.indexOf('click here for group info') > -1 ||
            title.indexOf('公告') > -1 ||
            title.indexOf('只有管理员可以发送消息') > -1
        ) return true;
        return false;
    }
    function handleFileInput(fileModal, btn, handler, plugin) {
        return new Promise(async (resolve) => {
            btn?.click();
            await EdtApi.sleep(200);
            let fileInput = fileModal.querySelector('div.lexical-rich-text-input>div[role="textbox"][data-lexical-editor="true"]');
            if (!fileInput) return resolve(true);//发送MP3等文件时，没有输入框
            fileInput.setAttribute("chat-id", handler.chatInfo.id);
            let msg = plugin.getIptMsg(fileInput);
            if (!handler.sendTrans(msg)) {
                let canSend = handler.canSend(fileInput, handler.settingInfo);
                if (!canSend) {
                    handler.showMessage("检测到中文，已阻止发送！");
                    return resolve(false);
                }
                return resolve(true);
            };
            handler.transToInput(fileInput, msg).then(result => {
                if (result) {
                    let canSend = handler.canSend(fileInput, handler.settingInfo);
                    if (!canSend) {
                        handler.showMessage("检测到中文，已阻止发送！");
                    }
                    resolve(canSend);
                } else {
                    resolve(false);
                }
            }).catch((error) => {
                console.error(error);
                resolve(false);
            });
        })
    }
    function openDB(dbName) {
        return new Promise(resolve => {
            let indexedDB = window.indexedDB;
            const request = indexedDB?.open(dbName, dbVersion);
            if (!request) return resolve(null);
            request.onsuccess = event => {
                indexdb = event.target?.result; // 数据库对象
                resolve(indexdb);
            };
            request.onerror = async (event) => {
                try {
                    let message = event?.target?.error?.message;
                    if (message?.includes("existing version (")) {
                        let arr = message.split("existing version (");
                        dbVersion = parseInt(arr[1].split(")")[0]);
                        console.log("dbVersion", dbVersion);
                    }
                } catch (error) {
                    console.error(error);
                }
                resolve(await openDB(dbName));
            }
        });
    }
    async function getVoiceId(msgId) {
        let dbName = 'model-storage',
            storeName = 'message';
        if (!indexdb) await openDB(dbName);
        if (!indexdb) return '';
        return new Promise(resolve => {
            let transaction = indexdb.transaction([storeName]);
            let objectStore = transaction.objectStore(storeName);
            console.log('getVoiceId:', msgId, objectStore);
            let request = objectStore.get(msgId);
            request.onsuccess = () => {
                resolve(request?.result?.filehash);
            };
            request.onerror = () => {
                resolve('');
            };
        });
    }
    function getVoiceFile(msgId) {
        return new Promise(async resolve => {
            try {
                let voiceId = await getVoiceId(msgId);
                if (!voiceId) return resolve(null);
                console.log('getVoiceFile', msgId, voiceId);
                let cacheName = 'lru-media-array-buffer-cache'; // 定义cache名称
                let path = `https://_media_cache_v2_.whatsapp.com/lru-media-array-buffer-cache_${encodeURIComponent(
                    voiceId,
                )}`; // 定义路径
                let cachesLocal = await caches.has(cacheName);
                //如果当前已有数据则直接获取缓存的数据
                if (!cachesLocal) return resolve(null);
                caches.match(path, { ignoreSearch: true }).then(async res => {
                    resolve(await res.arrayBuffer());
                }).catch(() => {
                    resolve(null);
                });
            } catch (error) {
                resolve(null);
            }
        });
    }
    function readAllByTable({ dbName, storeName }) {
        return new Promise(async (resolve, reject) => {
            if (!document.querySelector("#app header")) return resolve([]);
            if (!indexdb) await openDB(dbName);
            if (!indexdb) return reject(null);
            try {
                if (indexdb?.objectStoreNames?.contains(storeName)) {
                    let list = [];
                    const transaction = indexdb.transaction([storeName], 'readonly');
                    const objectStore = transaction?.objectStore(storeName);
                    // 获取所有数据
                    const cursorRequest = objectStore?.openCursor();
                    if (!cursorRequest) return resolve(null);
                    // 遍历数据
                    cursorRequest.onsuccess = function (event) {
                        const cursor = event.target?.result;
                        if (cursor) {
                            // 获取当前数据项
                            list.push(cursor.value);
                            // 继续遍历下一个数据项
                            cursor.continue();
                        } else {
                            // console.log('所有数据遍历完毕');
                            resolve(list);
                        }
                    };
                } else {
                    reject("查询失败！");
                }
            } catch (error) {
                console.error(error);
                reject(error);
            }
        });
    }
    function readChat() {
        return new Promise(resolve => {
            readAllByTable({ dbName: 'model-storage', storeName: 'chat' }).then(result => {
                resolve(result)
            });
        });
    }
    async function getUnread() {
        count = 0;
        try {
            chatResult = await readChat();
            if (!chatResult) return null;
            chatResult?.forEach(item => {//0==item.muteExpiration //非静音
                if ((item?.id?.includes("@c.us") || item?.id?.includes("@g.us")) && !item?.archive && -1 != item.muteExpiration && !item.isLocked && item.notSpam) count += item?.unreadCount > 0 ? item.unreadCount : 0;
            });
        } catch (error) { }
    }
    function initResize(view, handler) {
        let isResizing = false, startX = 0, startWidth = 0, percent = 0.40, currentX = 0, diffX = 0, newWidth = 0;
        let parentWidth = view.parentNode?.offsetWidth;
        let mwp = localStorage.getItem('menu-width-percent');
        if (mwp) percent = parseFloat(mwp);
        let otherWiew = document.querySelector("#app .two._aigs ._aigw.false");
        view.style.flex = `0 0 ${percent * 100}%`;
        if (otherWiew) otherWiew.style.flex = `0 0 ${percent * 100}%`;
        // console.log('initResize:', parentWidth);
        handler.addEventListener('mousedown', function (e) {
            startX = e.clientX;
            startWidth = view.offsetWidth;
            isResizing = true;
        });
        document.addEventListener('mousemove', function (e) {
            if (isResizing) {
                currentX = e.clientX;
                diffX = currentX - startX;
                newWidth = startWidth + diffX;
                percent = parseFloat((newWidth / parentWidth).toFixed(2));
                if (percent < 0.15) percent = 0.15;
                if (percent > 0.4) percent = 0.4;
                // console.log('percent：', percent);
                view.style.flex = `0 0 ${percent * 100}%`;
                if (otherWiew) otherWiew.style.flex = `0 0 ${percent * 100}%`;
            }
        });
        document.addEventListener('mouseup', function () {
            isResizing = false;
            localStorage.setItem('menu-width-percent', percent);
        });
    }
    function getTextByMsgBox(msgBox) {
        try {
            let texts = [], items = msgBox.querySelectorAll("span.selectable-text.copyable-text");
            items?.forEach((item) => {
                texts.push(item.textContent);
            });
            if (0 == texts.length) return "";
            return texts.join("\n");
        } catch (error) {
            console.error(error);
        }
        return "";
    }
    return {
        config: {
            friendList: '#pane-side,div.x1n2onr6.x1n2onr6.xyw6214.x78zum5.x1r8uery.x1iyjqo2.xdt5ytf.x6ikm8r.x1odjw0f.x1hc1fzr,[data-animate-modal-body="true"]>div.x12lqup9.x1o1kx08 div.x1n2onr6',
            chat: 'div[id="main"]',
            input: 'footer>div.copyable-area div.lexical-rich-text-input>div[role="textbox"][data-lexical-editor="true"],footer div[role="textbox"][data-lexical-editor="true"]',
            msgBox: 'div.copyable-area>div>div[role="application"][data-tab="8"]',
            inMsg: 'div.message-in div._akbu:not(.trans-inited)',
            outMsg: 'div.message-out div._akbu:not(.trans-inited)',
            allMsg: "div.message-in div._akbu,div.message-out div._akbu",
            voiceMsg: '.message-in ._ak49,.message-out ._ak4a,.message-in ._ak48,.message-out ._ak48',
            outVoice: {
                selector: "div.message-out",
                level: 10,
            },
            sendBtn: 'footer button[data-tab="11"]:not(.xjb2p0i,._aka_,.x1n7h9c3,.x1n2onr6)',
            setting: "footer > div.copyable-area div.lexical-rich-text-input",
            device: '#main header>div[role="button"]',
            files: {
                sendBtn: '.xh8yej3.x5yr21d>.xnpuxes.copyable-area div.x1n2onr6>div.xng8ra[role="button"][aria-label][tabindex="0"]',
                event: 'click'
            },
            tips: {
                in: '#main header>div.x78zum5.xdt5ytf.x1iyjqo2.xl56j7k.xeuugli',
                out: 'footer'
            },
            crm: {
                listener: '#pane-side',
                top: '#main header>div[role="button"]:nth-child(2)>div:nth-child(1)>div:nth-child(1)',
                left: '#app div.two._aigs div[role="listitem"] ._ak8l div._ak8o[role="gridcell"]',
                leftPosition: "prepend",
                loadOnChange: true
            },
            placeholder: {
                selector: 'footer > div.copyable-area div.lexical-rich-text-input>div.x10l6tqk.x13vifvy,footer > div.copyable-area div.lexical-rich-text-input>div[aria-hidden="true"]>div',
                update: true
            },
            extra: {//其他会触发对话框变动的情况处理
                selector: 'div[role="application"]>ul li',
                level: 6,
                delay: 600,
            },
            autoCount: 20,
            mainRequest: true,
            funcs: {
                fansDupl: true,
                workOrder: true,
                chatRecord: true
            }
        },
        async getWorkOrderInfos() {//获取工单信息
            try {
                chatResult = await readChat();
                if (!chatResult) return null;
                let infos = [], id;
                let lastWidMd = localStorage.getItem('last-wid-md')?.replace('"', '')?.split(':');
                let account = lastWidMd.length ? lastWidMd[0] : '';
                chatResult?.forEach(item => {
                    if ((item?.id?.includes("@c.us")) && "WhatsApp" != item.name) {
                        id = item.id.replace('@c.us', '');
                        if ("0" != id && id != account) {
                            infos.push({
                                fansId: item.id,
                                fansName: item.name
                            });
                        }
                    }
                });
                return infos;
            } catch (error) {
                return null;
            }
        },
        async getFriends() {
            try {
                chatResult = await readChat();
                if (!chatResult) return null;
                let friends = [], id;
                let lastWidMd = localStorage.getItem('last-wid-md')?.replace('"', '')?.split(':');
                let account = lastWidMd.length ? lastWidMd[0] : '';
                chatResult?.forEach(item => {
                    if ((item?.id?.includes("@c.us")) && "WhatsApp" != item.name) {
                        id = item.id.replace('@c.us', '');
                        if ("0" != id && id != account) {
                            friends.push({
                                id,
                                account: id,
                                name: item.name || id,
                            });
                        }
                    }
                });
                friendList = friends;
                return friends;
            } catch (error) {
                return null;
            }
        },
        init(_handler) {
            handler = _handler;
            isNewVersion = !handler?.pluginVersion ? false : handler?.pluginVersion >= 2.22;
            let str = localStorage.getItem("chat-id-map");
            if (str) chatIdMap = JSON.parse(str);
            this.updateChatIdMap();
            this.updateChatIdByChatName();
            readChat().then(res => chatResult = res);
            setTimeout(() => {
                if ('cookieStore' in window) {//强制切换语言
                    cookieStore.get('wa_web_lang_pref').then(res => {
                        // console.log('init：', res, res?.value);
                        if ("zh_CN" != res?.value) {
                            cookieStore.set(cookieStore.set({
                                domain: "web.whatsapp.com",
                                name: 'wa_web_lang_pref',
                                value: 'zh_CN',
                                partitioned: false,
                                path: "/",
                                secure: false,
                                expires: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) // 30 days from now
                            })).then(() => {
                                // console.log('init：', document.cookie);
                                // document.location.reload();
                            }).catch(error => {
                                // document.location.reload();
                                console.error(error);
                            });
                        }
                    });
                }
            }, 2000);
            console.log('init：初始化完成。');
            let btn = null, inputEl = null, canSend = false, msg;
            document.addEventListener('click', e => {
                btn = EdtApi.closest(e.target, 'div[data-animate-modal-backdrop="true"]>div[role="dialog"] div[role="button"][aria-disabled]', 5);
                if (btn) {//消息编辑翻译
                    inputEl = document.querySelector('div[data-animate-modal-backdrop="true"]>div[role="dialog"] div.lexical-rich-text-input>div[role="textbox"][data-lexical-editor="true"]');
                    if (inputEl) {
                        msg = this.getIptMsg(inputEl);
                        if (!handler.sendTrans(msg)) {
                            canSend = handler.canSend(inputEl, handler.settingInfo);//检测是否可以发送
                            if (!canSend) {
                                e.preventDefault();
                                e.stopPropagation();
                                e.stopImmediatePropagation();
                            }
                            return;
                        }
                        if (e.isTrusted) {//只处理主动点击的情况，有些应用音频发送由脚本触发
                            e.preventDefault();
                            e.stopPropagation();
                            e.stopImmediatePropagation();
                        } else return;
                        handler.transToInput(inputEl, msg).then(result => {
                            canSend = handler.canSend(inputEl, handler.settingInfo);
                            if (result && canSend) setTimeout(() => {
                                btn.click();
                            }, 200);
                        }).catch((error) => {
                            console.error(error);
                        });
                    }
                } else {
                    btn = EdtApi.closest(e.target, 'header>header div._ak4w._ak4x>ul>li>div[aria-label="已加星标消息"],section div.x13mwh8y.x1q3qbx4.x1wg5k15.x1bnvlk4.x1n2onr6.x1c4vz4f.x2lah0s.xdl72j9.x13x2ugz.xexx8yu.x18d9i69.xat24cr.xkhd6sd.x4uap5,section div.x13mwh8y.x1q3qbx4.x1wg5k15.x1bnvlk4.x1n2onr6.x1c4vz4f.x2lah0s.xdl72j9.x13x2ugz.xexx8yu.x6x52a7.x18d9i69.xxpdul3.xat24cr', 20);
                    if (btn) {//星标消息翻译
                        EdtApi.queryWait({ selector: 'div._aiwn._aiwm div._aigw>span.x10l6tqk.x13vifvy div.x5yr21d div[data-tab="3"],div.three._aigs div._aig- div.x5yr21d div[data-tab="3"]', all: true, timeout: 60000 }).then(msgBoxs => {
                            msgBoxs?.forEach(msgBox => {
                                let messages = msgBox.querySelectorAll('div[role="row"]>div[data-id] div.copyable-text>div._akbu:not(.trans-inited)');
                                messages?.forEach(item => {
                                    if (!item.classList.contains("trans-inited")) handler.initMessage({
                                        item,
                                        isOut: true
                                    });
                                });
                            });
                        }).catch(error => {
                            console.error(error);
                        });
                    }
                }
            }, true);
            EdtApi.queryWait({ selector: "#app .two._aigs>._aigw", timeout: 60000 }).then(view => {
                let handler = document.createElement("div");
                handler.className = "edt-resize-handler";
                view.append(handler);
                initResize(view, handler);
            }).catch(error => {
                console.error(error);
                setTimeout(() => {
                    this.init();
                }, 10000);
            });
            EdtApi.queryWait({ selector: '#side div._ak9t div.lexical-rich-text-input div[role="textbox"]', timeout: 60000 }).then(search => {
                search?.addEventListener("keyup", () => {
                    EdtApi.sleep(100).then(() => {
                        handler.updateLeftCrmInfos();
                    });
                });
            }).catch(error => {
                console.error(error);
            });
            EdtApi.queryWait({ selector: '#side div._ak9t div._ai04', timeout: 60000 }).then(search => {
                search?.addEventListener("click", () => {//主要处理清空按钮
                    EdtApi.sleep(100).then(() => {
                        handler.updateLeftCrmInfos();
                    });
                });
            }).catch(error => {
                console.error(error);
            });
        },
        updateChatIdMap(times = 0) {
            readChat().then(result => {
                if (result?.length > 0) {
                    result.forEach(item => {
                        if (item.name && (item?.id?.includes("@c.us") || item?.id?.includes("@g.us"))) {
                            chatIdMap[item.id] = item.name;
                            chatIdMap[item.name] = item.id;
                        }
                        localStorage.setItem("chat-id-map", JSON.stringify(chatIdMap));
                    });
                } else EdtApi.sleep(2000).then(() => {
                    times++;
                    if (times <= 20) this.updateChatIdMap(times);
                });
            });
        },
        updateChatIdByChatName(times = 0) {
            if (!isNewVersion) return;
            readChat().then(result => {
                if (result?.length > 0) {
                    console.log('updateChatIdByChatName:::', result, isNewVersion, handler.app.appId);
                    let friendIds = [];
                    result.forEach(item => {
                        if (item.name && (item?.id?.includes("@c.us") || item?.id?.includes("@g.us"))) {
                            friendIds.push({
                                id: item.id,
                                name: item.name
                            });
                        }
                    });
                    if (friendIds.length > 0) {
                        if (handler.updateSingleSettings) handler.updateSingleSettings(friendIds).then(res => {//更新独立设置
                            // console.log("updateSingleSettings:::", res);
                            handler.initSingleSettings();
                        }).catch(error => console.error(error));
                        if (EdtApi.doRequest && "true" != localStorage.getItem("chat-id-updated")) {
                            EdtApi.doRequest({
                                method: "put",
                                url: "/crm/user/friendIds",
                                data: {
                                    friendIds,
                                    appId: handler.app.appId
                                }
                            }).then(res => {
                                // console.log(res);
                                localStorage.setItem("chat-id-updated", "true");
                                handler.initCrmInfos();
                            }).catch(error => {
                                console.error(error);
                            });
                        }
                    }
                } else EdtApi.sleep(2000).then(() => {
                    times++;
                    if (times <= 20) this.updateChatIdByChatName(times);
                });
            });
        },
        getFriendAvatar(friendId) {
            let currentImg = document.querySelector('#side div[role="grid"]>div[role="listitem"] div[aria-selected="true"] ._ak8n img')
            return currentImg?.getAttribute('src') || "";
        },
        getMessageRecords({ box = document, handler, chatId }) {//获取聊天记录
            return new Promise((resolve) => {
                EdtApi.sleep(1000).then(async () => {//等待消息列表加载完成
                    chatId = await getChatId();
                    if (isGroup(chatId)) return resolve({});//群消息不处理
                    let friendName = await getChatTitle();
                    let messages = box.querySelectorAll(this.config.allMsg), records = [], id, content, time;
                    // console.log("messages:::", messages);
                    messages?.forEach(async item => {
                        content = await this.getText(item);
                        if (content) {
                            id = EdtApi.closest(item, 'div[data-id]', 10)?.getAttribute('data-id');
                            time = EdtApi.closest(item, 'div[data-pre-plain-text]', 5)?.getAttribute('data-pre-plain-text') || undefined;
                            if (time) time = EdtApi.formatDate(time);
                            records.push({
                                id,
                                content,
                                msgType: 1,
                                time: time,
                                timeString: EdtApi.formatDateTime(time),
                                transContent: handler.transCache[content],
                                isSend: item.classList?.contains("is-out"),
                            });
                        }
                    });
                    resolve({
                        records,
                        friendName,
                        friendId: chatId,
                    });
                });
            });
        },
        setTheme({ theme }) {
            localStorage.setItem("edt-theme", theme);
            setTheme(theme);
        },
        getDevice(item) {//获取设备
            let box = EdtApi.closest(item, 'div[data-id]');
            if (!box) return null;
            let dataId = box.getAttribute('data-id');
            if (!dataId) return null;
            let ids = dataId.split('us_'), id = ids[ids.length - 1], device = "";
            if (!id) return null;
            device = "android";
            if (id.startsWith("3A")) {
                device = "ios";
            } else if (id.startsWith("3E")) device = "web";
            return {
                box,
                device
            }
        },
        getCurrentDevice(msgList = document) {
            let items = (msgList || document).querySelectorAll('div.message-in');
            if (!items.length) return "";
            let deviceInfo = this.getDevice(items[items.length - 1]);
            return deviceInfo?.device || "";
        },
        getItemByChatId(chatId) {
            if (isNewVersion) {
                let chatMap, chatItem = chatResult?.find(item => item.id == chatId);
                if (chatItem) {
                    chatId = chatItem.name;
                } else {
                    chatMap = resolveChatIdMap(chatId);
                    chatId = chatMap?.name || chatId;
                }
            }
            let chatEl = document.querySelector(`#app div.two._aigs div[role="listitem"] div._ak8q span[dir="auto"][title="${chatId}"]`);
            if (!chatEl) return;
            return EdtApi.closest(chatEl, 'div[role="gridcell"]', 6);
        },
        _getItemByChatId(chatId) {
            let info = friendList?.find(item => item.id == chatId);
            if (!info) return null;
            let item = this.getItemByChatId(info.name), title, items;
            if (!item) {
                let nodeList = document.querySelectorAll('div[data-tab="4"] div[role="listitem"]');
                items = [...nodeList];
                item = items?.find(item => {
                    title = item.querySelector('div._ak8q span[dir="auto"][title]')?.title || "";
                    if (title) title = title.replace(/ /g, '').replace("+", '');
                    if (title == chatId) return true;
                    return false;
                });
                if (item) item = item.querySelector('div._ak8l');
            }
            return item;
        },
        resolveChatIdMap(key) {
            return resolveChatIdMap(key);
        },
        getChatIdByName(name) {
            let info = friendList?.find(item => item.name == name);
            if (!info) return null;
            return info.id;
        },
        getChatIdByItem(item) {
            let titleEl = item.querySelector('div._ak8q span[dir="auto"][title]');
            return titleEl?.title || "";
        },
        _getChatIdByItem(item) {
            let chatMap, id = this.getChatIdByItem(item);
            if (!id) return null;
            if (isNewVersion) {
                let chatItem = chatResult?.find(item => item.name == id);
                if (chatItem) {
                    id = chatItem.id;
                } else {
                    chatMap = resolveChatIdMap(id);
                    id = chatMap?.id || id;
                }
            }
            return id;
        },
        async getChatIds() {
            let items = document.querySelectorAll('div[role="listitem"] div._ak8q span[dir="auto"][title]');
            let ids = [], key, chatMap;
            if (isNewVersion) {
                chatResult = await readChat();
                if (chatResult) {
                    let chatItem, id;
                    items?.forEach(item => {
                        id = item.getAttribute('title');
                        if (!ids.includes(id)) ids.push(id);
                        chatItem = chatResult?.find(item => item.name == id);
                        if (chatItem) {
                            id = chatItem.id;
                        } else {
                            chatMap = resolveChatIdMap(id);
                            id = chatMap?.id || id;
                        }
                        if (!ids.includes(id)) ids.push(id);
                    });
                } else items?.forEach(item => {
                    key = item.getAttribute('title');
                    chatMap = resolveChatIdMap(key);
                    ids.push(chatMap?.id || key);
                });
            } else items?.forEach(item => {
                key = item.getAttribute('title');
                chatMap = resolveChatIdMap(key);
                ids.push(chatMap?.id || key);
            });
            // console.log("getChatIds:::", ids);
            return ids;
        },
        async getChatTitle() {
            let title = await getChatTitle();
            return title;
        },
        getUnread() {
            let curCount = count;
            getUnread();
            return curCount;
        },
        isCanScroll(e) {
            if (!e) return false;
            let target = e.srcElement || e.target;
            if (!target) return false;
            if (document.querySelector('#pane-side')?.contains(target)) {
                let extraEl = document.querySelector('#side div.lexical-rich-text-input>div[role="textbox"]');
                if (extraEl && this.getIptMsg(extraEl)) return false;
                return true;
            }
            return false;
        },
        getChatInfo(e) {
            let canScroll = this.isCanScroll(e);//必须在此处判断，不然页面元素可能会变动
            // console.log("canScroll:", canScroll);
            return new Promise(async (resolve) => {
                chatId = await getChatId();
                console.log("getChatInfo:::", chatId);
                resolve({ id: chatId, title: await getChatTitle(), isGroup: isGroup(chatId) });
                canScroll && this.scrollToBottom();
            });
        },
        getText(msgBox) {
            return new Promise((resolve) => {
                if (!msgBox) return resolve("");
                let text = "";
                let moreBtn = msgBox.querySelector(".read-more-button");
                if (moreBtn) {
                    moreBtn?.click();//点击更多
                    setTimeout(() => {
                        text = getTextByMsgBox(msgBox);
                        resolve(text);
                    }, 200);
                } else {
                    text = getTextByMsgBox(msgBox);
                    resolve(text);
                }
            });
        },
        getIptText(inputEl) {
            if (!inputEl) return '';
            try {
                let texts = [], items = inputEl.querySelectorAll('p.selectable-text.copyable-text>span.selectable-text.copyable-text');
                items?.forEach((item) => {
                    texts.push(item.textContent);
                });
                if (0 == texts.length) return "";
                return texts.join("\n");
            } catch (error) {
                console.error(error);
            }
            return "";
        },
        getIptMsg(inputEl) {
            if (!inputEl) return '';
            try {
                // 只有表情，没有文字不翻译
                if (!inputEl.querySelector('span.selectable-text.copyable-text')) return '';
                let texts = [], items = inputEl.querySelectorAll('p.selectable-text.copyable-text');
                items?.forEach((item) => {
                    texts.push(item.textContent);
                });
                if (0 == texts.length) return "";
                return texts.join("\n");
            } catch (error) {
                console.error(error);
            }
            return "";
        },
        async getVoice(msgBox) {
            let msgId = this.getMsgId(msgBox);
            if (!msgId) return null;
            let file = await getVoiceFile(msgId);
            console.log('获取语音数据成功：', msgId, file);
            return {
                file,
                msgId,
                format: "ogg"
            }
        },
        getMsgId(msgBox) {
            let msgId = null;
            let msgEl = EdtApi.closest(msgBox, "div[data-id]", 10);
            if (msgEl) msgId = msgEl.getAttribute('data-id');
            return msgId;
        },
        beforeSend({ handler, inputEl }) {
            let obj = {
                result: true,
                fileInput: null
            };
            return new Promise(async (resolve) => {
                let fileModal = document.querySelector('div.xh8yej3.x5yr21d>.xnpuxes.copyable-area');
                if (!fileModal) return resolve(obj);
                let fileBtns = fileModal.querySelectorAll('div[role="listitem"] button._ak3k');
                if (!fileBtns || 0 == fileBtns.length) return resolve(obj);
                let btn, result = false;
                if (inputEl && this.getIptMsg(inputEl)) {//发送文件时先清空原输入框内容
                    result = await handler.inputMsg(inputEl, " ");
                    if (!result) {
                        obj.result = false;
                        return resolve(obj);
                    }
                }
                for (btn of fileBtns) {
                    result = await handleFileInput(fileModal, btn, handler, this);
                    if (!result) {
                        obj.result = false;
                        return resolve(obj);
                    }
                }
                let sendBtn = fileModal.querySelector(this.config.files.sendBtn);
                sendBtn?.click();
                obj.result = false;
                resolve(obj);
            });
        },
        handlerEnter() {
            let num = 0;
            scrollTimer && clearInterval(scrollTimer);
            scrollTimer = setInterval(() => {
                scrollView = document.querySelector('#main div.x1rife3k[tabindex="0"]');
                if (scrollView) {
                    scrollView.scrollTo({
                        top: scrollView.scrollHeight - scrollView.clientHeight,
                        behavior: 'smooth' // 平滑滚动
                    });
                }
                num++;
                if (num >= 3) {
                    clearInterval(scrollTimer);
                    scrollTimer = null;
                    scrollView = null;
                }
            }, 200);
        },
        scrollToBottom() {//有些版本是button，有些版本是div
            let scrollBtn = document.querySelector('#main div[role="button"][data-tab="7"],#main button[type="button"][data-tab="7"]');
            scrollBtn?.click();
            this.handlerEnter();
        },
        getUserInfo() {
            try {
                let lastWidMd = localStorage.getItem('last-wid-md')?.replace('"', '')?.split(':');
                let avatar = (localStorage.getItem('WACachedProfilePicEURL') || '')?.replace(/(^["])|(["]$)/g, '');
                let account = lastWidMd.length ? lastWidMd[0] : '';
                let userName = localStorage.getItem("XtLS3FpBWI6+xj6cM+/cVA==") || localStorage.getItem("2Y2rNUuZPYSctrR9F59W2w==") || localStorage.getItem("vM7NbXIMQbUtsA7eR1YtOw==");
                userName = userName?.replace(/"/g, '') || account;
                return {
                    avatar,
                    account: `${account}@c.us`,
                    userName,
                    toDataUrl: true
                };
            } catch (error) {
                return null;
            }
        }
    }
};